#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif

#define tb_malloc malloc
#define tb_free free

#ifdef PATH_MAX
#define TB_PATH_MAX PATH_MAX
#else
#define TB_PATH_MAX 4096
#endif

enum {
    TB_EOK = 0,
    TB_ERR,
};

typedef struct {
    const char *name; // env: TERM
    const char *path; // pull path of terminfo database
    const char *caps[32];
    char *base;
    size_t size;
} tb_context_t;

static int tinfo_load_by_path(tb_context_t *tb, const char *path, const char *term) {
    char buf[TB_PATH_MAX];

    snprintf(buf, sizeof(buf), "%s/%c/%s", path, term[0], term);

    FILE *fp = fopen(buf, "rb");
    if (fp == NULL) {
        return TB_ERR;
    }

    struct stat st;
    if (fstat(fileno(fp), &st) != 0) {
        fclose(fp);
        return TB_ERR;
    }

    size_t fsize = st.st_size;

    char *data = (char *)tb_malloc(fsize);
    if (!data) {
        fclose(fp);
        return TB_ERR;
    }

    if (fread(data, 1, fsize, fp) != fsize) {
        fclose(fp);
        tb_free(data);
        return TB_ERR;
    }

    tb->base = data;
    tb->size = fsize;

    fclose(fp);
    return 0;
}

static int tinfo_parse(tb_context_t *tb)
{
    int16_t *header = (int16_t *)tb->base;

    // term
    printf("\n[header]\n");
    printf("magic              (%o)\n", header[0]);
    printf("name bytes          %d\n",  header[1]);
    printf("bool flags bytes    %d\n",  header[2]);
    printf("short integers      %d\n",  header[3]);
    printf("offsets             %d\n",  header[4]);
    printf("string-table bytes  %d\n",  header[5]);
    printf("\n");

    char buf[2046];
    memset(buf, 0, sizeof(buf));

    char *parser;
    parser= tb->base + sizeof(uint16_t) * 6;
    memcpy(buf, parser, header[1]);
    printf("name: %s\n", buf);

    return 0;
}

static int tinfo_init()
{
    return 0;
}

int main(int argc, char *argv[])
{
    tb_context_t _tb = {0};
    tb_context_t *tb = &_tb;

    const char *_paths[] = {
        "/usr/local/etc/terminfo",
        "/usr/local/share/terminfo",
        "/usr/local/lib/terminfo",
        "/etc/terminfo",
        "/usr/share/terminfo",
        "/usr/lib/terminfo",
        "/usr/share/lib/terminfo",
        "/lib/terminfo",
    };

    char *term = getenv("TERM");
    if (term == NULL) {
        return -1;
    }

    tb->base = NULL;

    for (int i = 0; i < ARRAY_SIZE(_paths); i++) {
        if(tinfo_load_by_path(tb, _paths[i], term) == TB_EOK) {
            tb->path = _paths[i];
            break;
        }
    }

    if (tb->base != NULL)
        printf("tinfo: %s, size: %ld\n", tb->path, tb->size);

    tinfo_parse(tb);

    return 0;
}
